/**
 * @author casazaft
 */
(function(){
    window.j2j = {};
    j2j.unique = function(){
        var id = 1;
        return function(){
            return ++id;
        };
    }();
    var pCheckRe = /[^a-z\d.]/;
    var cCheckRe = /^[A-Z]/;
    var TOPBASECLASS = "j2j.lang.Object";
    
    j2j.Package = function(ns, fn){
        /*if (this != window) 
         throw Error('you can`t instance a package!');*/
        var scopePackage = Package.namespace(ns);
        if (!scopePackage.name) {
            scopePackage.name = ns;
        }
        return {
            scope: scopePackage,
            Class: j2j.Class,
            Interface: j2j.Interface
        };
    };
    j2j.Package.namespace = function(ns){
        if (pCheckRe.test(ns)) {
            throw Error("Package" + ns + " name must be all lowercases");
        }
        var base = window;
        var nss = ns.split('.');
        var length = nss.length;
        for (var i = 0; i < length; i++) {
            var part = nss[i];
            if (!base[part]) {
                base[part] = {};
            }
            else 
                if (typeof base[part] != "object") {
                    throw Error("can not create namespace!");
                }
            base = base[part];
        }
        if (!base.exportTo) {
            base.exportTo = function(targetPackage){
                for (var p in base) {
                    if (typeof base[p] != 'function') {
                        continue;
                    }
                    if (!targetPackage[p]) {
                        targetPackage[p] = base[p];
                    }
                }
            };
        }
        return base;
    };
    
    j2j.Import = function(src, dest){
    
        var destClass = j2j.Class.forName(src);
        var name = destClass.getName();
        if (dest) {
            dest[name] = destClass;
        }
        return destClass;
    };
    j2j.Class = function(className, classMeta){
        if (!cCheckRe.test(className)) {
            throw Error(className + " is a illegal Classname!");
        }
        if (!this.scope) {
            throw Error('can not direct call Class function');
        }
        if (!classMeta[className]) {
            throw Error(className + ' did not define constructor function');
        }
        var classConstructor = classMeta[className];
        var currentPackage = this.scope;
        var classRef;
        var sp = classMeta.Extends;
        if (sp) {
            if (typeof sp == 'string') {
                sp = j2j.Class.forName(sp);
            }
        }
        else {
            sp = j2j.Class.forName(TOPBASECLASS);
        }
        var sb = function(){
            var _sp = sp;
            var _currentPackage = currentPackage;
            var _classConstructor = classConstructor;
            var _className = className;
            return function(){
                if (_currentPackage == this) {
                    throw Error("In j2j,you must be using the 'new' operator to instance the " + _className + " Class!");
                }
                _sp.apply(this, arguments);
                return _classConstructor.apply(this, arguments);
            };
        }();
        classRef = currentPackage[className] = j2j.Class.defineClass(sb, sp, classMeta);
        classRef._name = className;
        classRef.prototype._classRef = classRef;
        classRef.exportTo = function(dest){
            dest[className] = classRef;
        };
        sp = null;
        currentPackage = null;
        classConstructor = null;
        sb = null;
        return classRef;
    };
    
    
    j2j.Class.defineClass = function(sb, sp, overrides){
        var oc = Object.prototype.constructor;
        if (typeof sp == 'object') {
            overrides = sp;
            sp = sb;
            sb = overrides.constructor != oc ? overrides.constructor : function(){
                sp.apply(this, arguments);
            };
        }
        var spp = sp.prototype;
        var F = function(){
        };
        var Prototype = overrides.Prototype;
        var Statics = overrides.Statics;
        //添加或者改写实例方法    
        F.prototype = spp;
        sb.prototype = new F();
        var sbp = sb.prototype;
        if (Prototype) {
            j2j.Class.overrides(sbp, Prototype);
            
        }
        sbp.Super = spp;
        sbp.constructor = sb;
        if (spp.constructor == oc) {
            spp.constructor = sp;
        }
        //继承类静态方法和属性
        j2j.Class.overrides(sb, sp);
        //添加类静态方法
        if (Statics) {
            j2j.Class.overrides(sb, Statics);
        }
        
        return sb;
    };
    
    j2j.Class.overrides = function(dest, overrides){
        for (var method in overrides) {
            if (method != 'prototype') {
                dest[method] = overrides[method];
            }
        }
    };
    
    
    j2j.Class.forName = function(className){
        if (typeof className != 'string') {
            throw Error('Class.forName() must pass a String parameter');
        }
        var result = null;
        var classRealName = null;
        var container = null;
        if (className.indexOf('.') != -1) {
            var ns = className.split('.');
            classRealName = ns.pop();
            ns = ns.join('.');
            container = j2j.Package.namespace(ns);
        }
        else {
            classRealName = className;
            container = window;
        }
        result = container[classRealName];
        if (!result || typeof result != 'function') {
            throw Error('there is no Class ' + className);
        }
        return result;
    };
    j2j.Package.namespace("j2j").exportTo(window);
})();

/**
 * @author casazaft
 */
//基础类库
(function(){
    Package("j2j.lang").Class("Object", {
        //构造函数
        Object: function(){
            this._j2jhash = j2j.unique();
        },
        Statics: {
        
            getName: function(){
                return this._name;
            }
        },
        Prototype: {
            clone: function(){
                throw Error("do not support clone now!");
            },
            hashCode: function(){
                return this._j2jhash;
            },
            getClass: function(){
                return this._classRef;
            },
            toString: function(){
                var str = [];
                for (var p in this) {
                    if (this[p] === this) {
                        continue;
                    }
                    str[str.length] = p + ":" + this[p].toString();
                }
                str = str.join(",");
                str = "{" + str + "}";
                return str;
            },
            equals: function(obj){
                var result = false;
                for (var p in this) {
                    if (this[p].equals) {
                        result = this[p].equals(obj[p]);
                    }
                    else {
                        result = (this[p] === obj[p]);
                    }
                    if (!result) {
                        return result;
                    }
                }
                return result;
            },
            finalize: function(obj){
                obj = obj || this;
                j2j.lang.System.setGC(obj);
            }
        },
        Extends: Object
    });
    
    Package("j2j.patterns").Class("Singleton", {
        Singleton: function(){
            var thisClass = this.getClass();
            if (typeof thisClass._instance == 'function') 
                thisClass._instance = new thisClass._instance();
            if (thisClass._instance.getInstance() != null) 
                throw Error("Class " + this.Name + thisClass.SINGLETON_MSG);
            thisClass._instance.setInstance(this);
        },
        Statics: {
            _instance: function(){
                var instance = null;
                return {
                    getInstance: function(){
                        return instance;
                    },
                    setInstance: function(p){
                        instance = p;
                    }
                };
            },
            SINGLETON_MSG: ' is Singleton',
            getInstance: function(){
                if (typeof this._instance == 'function') 
                    this._instance = new this._instance();
                if (this._instance.getInstance() == null) {
                    var classRef = this;
                    this._instance.setInstance(new classRef(arguments));
                }
                return this._instance.getInstance();
            }
        }
    });
    Package("j2j.io").Class("PrintStream", {
        PrintStream: function(){
            var pRe = /\{(\d+)\}/g;
            this.format = function(str){
                var match, rp, args = arguments, result;
                result = str.replace(pRe, function($, $1){
                    rp = parseInt($1, 10) + 1;
                    rp = args[rp] + "";
                    return rp;
                });
                return result;
            };
        },
        Extends: j2j.patterns.Singleton
    });
    Package("j2j.lang").Class("GarbageCollector", {
        GarbageCollector: function(){
            var garbage = [];
            var finalize = function(obj){
                for (var p in obj) {
                    if (obj.hasOwnProperty(p)) {
                        delete obj[p];
                        
                    }
                    else {
                        obj[p] = null;
                        
                    }
                    
                }
            };
            this.clean = function(){
                var obj;
                while (garbage.length) {
                    obj = garbage.pop();
                    finalize(obj);
                    delete obj;
                }
                if (window.CollectGarbage) {
                    CollectGarbage();
                }
            };
            this.setGC = function(obj){
                garbage.push(obj);
            };
        },
        Extends: j2j.patterns.Singleton
    });
    Package("j2j.lang").Class("System", {
        System: function(){
            throw Error('u can`t use this funcation directly!');
        },
        Statics: function(){
            var setGC = function(obj){
                this.gcRunner.setGC(obj);
            };
            var gc = function(){
                this.gcRunner.clean();
            };
            return {
                out: j2j.io.PrintStream.getInstance(),
                gcRunner: j2j.lang.GarbageCollector.getInstance(),
                setGC: setGC,
                gc: gc,
                env: function(){
                    var ua = navigator.userAgent.toLowerCase();
                    var isStrict = document.compatMode == "CSS1Compat", isOpera = ua.indexOf("opera") > -1, isSafari = (/webkit|khtml/).test(ua), isSafari3 = isSafari && ua.indexOf('webkit/5') != -1, isIE = !isOpera && ua.indexOf("msie") > -1, isIE7 = !isOpera && ua.indexOf("msie 7") > -1, isGecko = !isSafari && ua.indexOf("gecko") > -1, isGecko3 = !isSafari && ua.indexOf("rv:1.9") > -1, isBorderBox = isIE && !isStrict, isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1), isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1), isAir = (ua.indexOf("adobeair") != -1), isLinux = (ua.indexOf("linux") != -1), isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
                    if (isIE && !isIE7) {
                        try {
                            document.execCommand("BackgroundImageCache", false, true);
                        } 
                        catch (e) {
                        }
                    }
                    return {
                        isStrict: isStrict,
                        isOpera: isOpera,
                        isSafari: isSafari,
                        isSafari3: isSafari3,
                        isIE: isIE,
                        isIE7: isIE7,
                        isGecko: isGecko,
                        isGecko3: isGecko3,
                        isBorderBox: isBorderBox,
                        isWindows: isWindows,
                        isMac: isMac,
                        isAir: isAir,
                        isLinux: isLinux,
                        isSecure: isSecure
                    };
                }()
            };
        }()
    });
    Package.namespace("j2j.lang").exportTo(window);
})();

